% main.m
% MATLAB 版本的主执行脚本。
% *** 最终版: 为所有前沿解创建独立文件夹并保存全套结果，特殊命名关键解 ***
clear; clc; close all;
rng('default')
rng(1)
% --- 1. 设置参数 ---
case_name = 'FlashAttention_Case1';
fprintf('--- 正在处理算例: %s ---\n', case_name);
% 定义硬件容量
caps = struct('l1', 4096, 'ub', 1024, 'l0a', 256, 'l0b', 256, 'l0c', 512);
% 定义初始策略控制参数
params = struct();
params.min_farthest_use_threshold = 100; 
params.w_use = 0.5; 
params.w_vol = 0.3; 
params.w_vic = 0.2; 
%% 定义优化器 options
% 自动探测本地可用核心/worker 数量，用于设置种群规模，便于验证性实验快速收敛
try
    cluster_info = parcluster('local');
    core_num = cluster_info.NumWorkers;
catch
    core_num = feature('numcores');
end
core_num = max(1, core_num); % 防止返回异常值

options = struct();
options.generations = 2;
options.population_size = 2;
options.batch_size = options.population_size;
options.schedule_move_prob = 0.75;
options.threshold_range = [50, 800];
%% --- 2. 加载计算图和调度文件 ---
nodes_file = [case_name, '_Nodes.csv'];
edges_file = [case_name, '_Edges.csv'];
[graph, code_map] = load_graph(nodes_file, edges_file);
fprintf('计算图加载完成。\n');
p1_schedule_file = [case_name, '_final_schedule_optimized.txt'];
p1_schedule = load_schedule_from_file(p1_schedule_file);
fprintf('问题1调度结果加载完成，将使用 %d 个节点进行优化。\n', length(p1_schedule));
%% --- 3. 调用多目标优化器 ---
fprintf('\n--- 开始执行多目标优化 ---\n');
[pareto_front] = optimizer_v3_nsga(p1_schedule, graph, code_map, caps, params, options);
fprintf('--- 多目标优化完成 ---\n');
%% --- 4. 结果处理与保存 ---
fprintf('\n--- 优化结果: 找到 %d 个帕累托最优解 ---\n', length(pareto_front));
if ~isempty(pareto_front)
    % --- a. 创建主输出目录并筛选关键解 ---
    case_output_dir = fullfile('Problem3_MATLAB', case_name);
    if ~exist(case_output_dir, 'dir'), mkdir(case_output_dir); end
    
    all_times = double([pareto_front.time]);
    all_spills = double([pareto_front.spill]);
    
    [~, min_time_idx] = min(all_times);
    [~, min_spill_idx] = min(all_spills);
    
    norm_times = (all_times - min(all_times)) / max(1, max(all_times) - min(all_times));
    norm_spills = (all_spills - min(all_spills)) / max(1, max(all_spills) - min(all_spills));
    distances = sqrt(norm_times.^2 + norm_spills.^2);
    [~, min_dist_idx] = min(distances);
    best_time_sol = pareto_front(min_time_idx);
    best_spill_sol = pareto_front(min_spill_idx);
    best_tradeoff_sol = pareto_front(min_dist_idx);
    visualize_pareto_front(pareto_front, best_time_sol, best_spill_sol, best_tradeoff_sol, case_output_dir, case_name);
    
    % === 保存帕累托前沿到CSV文件 ===
    fprintf('\n--- 保存帕累托前沿到CSV文件 ---\n');
    pareto_csv_file = fullfile(case_output_dir, [case_name, '_pareto_solutions.csv']);
    fid = fopen(pareto_csv_file, 'w');
    
    if fid ~= -1
        % 写入CSV表头
        fprintf(fid, 'solution_id,time,spill,strategy_type,min_farthest_use_threshold,w_use,w_vol,w_vic\n');
        
        % 写入每个帕累托解的数据
        for i = 1:length(pareto_front)
            solution = pareto_front(i);
            
            % 获取策略类型 (如果params中有alloc_strategy字段)
            if isfield(solution.params, 'alloc_strategy')
                strategy_type = solution.params.alloc_strategy;
            else
                strategy_type = 'unknown';  % 默认值
            end
            
            fprintf(fid, '%d,%.2f,%.2f,%s,%.2f,%.2f,%.2f,%.2f\n', ...
                i, ...                                           % solution_id
                solution.time, ...                              % time
                solution.spill, ...                             % spill
                strategy_type, ...                              % strategy_type
                solution.params.min_farthest_use_threshold, ... % threshold
                solution.params.w_use, ...                      % w_use
                solution.params.w_vol, ...                      % w_vol
                solution.params.w_vic);                         % w_vic
        end
        
        fclose(fid);
        fprintf('  ✓ 帕累托前沿已保存到: %s\n', pareto_csv_file);
        fprintf('  ✓ 总解决方案数: %d\n', length(pareto_front));
    else
        fprintf('  ✗ 错误: 无法创建CSV文件!\n');
    end
    
    % --- b. 循环处理所有解：验证并保存文件 ---
    fprintf('\n--- 开始对所有最优解进行验证与文件保存 ---\n');
    solution_dirs = cell(length(pareto_front), 1);
    solution_folder_names = cell(length(pareto_front), 1);
    for i = 1:length(pareto_front)
        
        current_solution_from_front = pareto_front(i);
        
        % 文件夹命名策略
        folder_name = sprintf('Solution_%02d', i);
        if i == min_time_idx, folder_name = [folder_name, '_Best_Time']; end
        if i == min_spill_idx, folder_name = [folder_name, '_Best_Spill']; end
        if i == min_dist_idx, folder_name = [folder_name, '_Best_Tradeoff']; end
        
        fprintf('\n---------------------------------------------------\n');
        fprintf('--- 正在处理解 #%d (%s) ---\n', i, folder_name);
        
        solution_dir = fullfile(case_output_dir, folder_name);
        if ~exist(solution_dir, 'dir'), mkdir(solution_dir); end
        solution_dirs{i} = solution_dir;
        solution_folder_names{i} = folder_name;
        
        % 重新评估以获取完整的 solution 和 graph 对象
        [~, ~, solution, final_graph] = evaluate_schedule(current_solution_from_front.schedule, graph, code_map, caps, current_solution_from_front.params, []);
        
        % 对每个解进行验证
        fprintf('--- 开始验证 (用于保存) ---\n');
        is_valid = validate_solution(solution, final_graph, code_map, caps.l1, caps.ub, caps.l0a, caps.l0b, caps.l0c);
        
        if is_valid
            fprintf('  验证通过。开始保存TXT文件...\n');
            write_schedule_to_file(fullfile(solution_dir, [case_name, '_schedule.txt']), solution.final_schedule);
            write_memory_to_file(fullfile(solution_dir, [case_name, '_memory.txt']), solution.memory_offsets);
            spill_log_for_file = format_spill_log_for_output(solution.spill_map, final_graph);
            write_spill_to_file(fullfile(solution_dir, [case_name, '_spill.txt']), spill_log_for_file);
            fprintf('  TXT结果已保存至: %s\n', solution_dir);
        else
            fprintf('!!! 验证失败: 解 #%d 存在问题，将不保存文件 !!!\n', i);
            continue; % 如果验证失败，则跳过后续所有操作
        end
    end
    fprintf('\n--- 所有解的文件保存完成。 ---\n');
end
%% --- 5. 结果可视化 ---
if ~isempty(pareto_front)
    % --- a. 绘制全局帕累托前沿图 ---
    fprintf('\n--- 开始进行结果可视化 ---\n');
    fprintf('  帕累托最优前沿图已保存至: %s\n', fullfile(case_output_dir, [case_name, '_pareto_front.png']));

    % --- b. 循环处理关键解：二次验证并生成详细图表 ---
    fprintf('\n--- 开始为关键解生成详细图表 ---\n');
    key_indices = unique([min_time_idx, min_spill_idx, min_dist_idx]); % 使用unique避免重复处理
    
    for k = 1:length(key_indices)
        key_idx = key_indices(k);
        current_solution_from_front = pareto_front(key_idx);
        
        key_name = sprintf('解 #%d', key_idx);
        if key_idx == min_time_idx, key_name = [key_name, ' (Best_Time)']; end
        if key_idx == min_spill_idx, key_name = [key_name, ' (Best_Spill)']; end
        if key_idx == min_dist_idx, key_name = [key_name, ' (Best_Tradeoff)']; end
        
        fprintf('\n---------------------------------------------------\n');
        fprintf('--- 正在为关键解 [%s] 生成图表 ---\n', key_name);

        % 重新评估以获取绘图所需的完整对象
        [~, ~, solution, final_graph] = evaluate_schedule(current_solution_from_front.schedule, graph, code_map, caps, current_solution_from_front.params, []);
        
        % 根据您的要求，在绘图前进行再次验证
        fprintf('--- 开始再次验证 (用于绘图) ---\n');
        is_valid_for_viz = validate_solution(solution, final_graph, code_map, caps.l1, caps.ub, caps.l0a, caps.l0b, caps.l0c);
        
        if is_valid_for_viz
            fprintf('  验证通过。开始生成详细可视化图表...\n');
            history = run_simulation_for_viz(solution, final_graph, code_map, caps.l1, caps.ub, caps.l0a, caps.l0b, caps.l0c);
            target_type_code = code_map.L1;
            target_capacity = caps.l1;
            solution_dir = '';
            folder_tag = sprintf('Solution_%02d', key_idx);
            if key_idx <= length(solution_dirs) && ~isempty(solution_dirs{key_idx})
                solution_dir = solution_dirs{key_idx};
                folder_tag = solution_folder_names{key_idx};
            else
                solution_dir = fullfile(case_output_dir, folder_tag);
                if ~exist(solution_dir, 'dir'), mkdir(solution_dir); end
            end
            file_prefix = sprintf('%s_%s', case_name, folder_tag);
            visualize_fragmentation(history, target_type_code, solution_dir, file_prefix);
            visualize_gantt_chart(history, target_type_code, target_capacity, solution_dir, file_prefix);
            visualize_buffer_lifetimes(history, target_type_code, solution_dir, file_prefix);
            fprintf('  为关键解 [%s] 生成的详细图表已保存至 %s。\n', key_name, solution_dir);
        else
            fprintf('!!! 再次验证失败: 关键解 [%s] 存在问题，无法生成图表 !!!\n', key_name);
        end
    end
    
    fprintf('\n---------------------------------------------------\n');
    fprintf('--- 所有后处理已完成。 ---\n');
end